﻿using System;
using System.IO;
using System.Reflection;
using System.Linq.Expressions;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
using Go;

namespace GoRpc
{
    static public partial class Rpc
    {
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
        public sealed class ParamTuple : Attribute
        {
            public readonly bool Internal;
            public readonly string Name;

            public ParamTuple(string Name)
                : this(Name, false) { }

            internal ParamTuple(string Name, bool Internal)
            {
                this.Internal = Internal;
                this.Name = Name;
            }

            static public void AssertName()
            {
                Serializer.Initialize();
            }
        }

        [AttributeUsage(AttributeTargets.Field)]
        public sealed class ParamName : Attribute
        {
            public readonly string Name;

            public ParamName(string Name)
            {
                this.Name = Name;
            }
        }

        [ParamTuple("__GoRpc_LostTuple__", true)]
        abstract public class LostTuple
        {
            Dictionary<string, object> LostDict;

            internal void AddLost(string Name, object Value)
            {
                if (LostDict == null)
                {
                    LostDict = new Dictionary<string, object>();
                }
                LostDict[Name] = Value;
            }

            public Dictionary<string, object> Dict
            {
                get
                {
                    return LostDict;
                }
            }
        }

        private class SerializationException : Exception
        {
            public SerializationException(string typeName, string assemblyName, Exception innerException = null)
                : base($"无法序列化类型: {typeName} (程序集: {assemblyName})", innerException) { }
        }

        private class DeserializeException : Exception
        {
            public DeserializeException(string typeName, string assemblyName, Exception innerException = null)
                : base($"无法反序列化类型: {typeName} (程序集: {assemblyName})", innerException) { }
        }

        class Serializer
        {
            struct TypeInfo
            {
                static private string[] ArrayTails = new string[]
                {
                    "",
                    "[]",
                    "[,]",
                    "[,,]",
                    "[,,,]",
                };

                public bool Internal;
                public string SerializationName;

                public TypeInfo(Type type)
                {
                    Internal = false;
                    SerializationName = ParseType(type);
                }

                unsafe static private string ParseType(Type type)
                {
                    Type baseType = type;
                    bool isArray = type.IsArray;
                    bool arrayIt = baseType.IsArray;
                    while (arrayIt)
                    {
                        int rank = type.GetArrayRank();
                        if (rank >= ArrayTails.Length)
                        {
                            throw new SerializationException($"{type.FullName} Rank错误", type.Assembly.FullName);
                        }
                        baseType = baseType.GetElementType();
                        if (baseType == null)
                        {
                            throw new SerializationException($"{type.FullName} 错误", type.Assembly.FullName);
                        }
                        arrayIt = baseType.IsArray;
                    }
                    ParamTuple nameAttr = (ParamTuple)Attribute.GetCustomAttribute(baseType, typeof(ParamTuple), false);
                    if (null == nameAttr)
                    {
                        switch (Type.GetTypeCode(baseType))
                        {
                            case TypeCode.Boolean:
                            case TypeCode.Char:
                            case TypeCode.SByte:
                            case TypeCode.Byte:
                            case TypeCode.Int16:
                            case TypeCode.UInt16:
                            case TypeCode.Int32:
                            case TypeCode.UInt32:
                            case TypeCode.Int64:
                            case TypeCode.UInt64:
                            case TypeCode.Single:
                            case TypeCode.Double:
                            case TypeCode.Decimal:
                            case TypeCode.DateTime:
                            case TypeCode.String:
                                return type.FullName;
                            case TypeCode.Object:
                                if (baseType == typeof(object))
                                {
                                    return type.FullName;
                                }
                                break;
                        }
                        throw new SerializationException($"{type.FullName} 错误", type.Assembly.FullName);
                    }
                    string serializationName;
                    string attrName = string.Concat(baseType.Namespace, ".", nameAttr.Name);
                    if (baseType.IsGenericType)
                    {
                        Type[] genericTypes = baseType.GetGenericArguments();
                        for (int i = 0; i < genericTypes.Length; i++)
                        {
                            attrName = string.Concat(attrName, "<", ParseType(genericTypes[i]), ">");
                        }
                    }
                    if (isArray)
                    {
                        string typeName = type.FullName;
                        int firstBracket = FirstArrayBracket(typeName);
                        int len1 = attrName.Length;
                        int len2 = typeName.Length - firstBracket;
                        serializationName = new string('\0', len1 + len2);
                        fixed (char* dst_ = serializationName)
                        {
                            char* dst = dst_;
                            fixed (char* src_ = attrName)
                            {
                                char* src = src_;
                                for (int i = len1; i > 0; i--)
                                {
                                    *(dst++) = *(src++);
                                }
                            }
                            fixed (char* src_ = typeName)
                            {
                                char* src = src_ + firstBracket;
                                for (int i = len2; i > 0; i--)
                                {
                                    *(dst++) = *(src++);
                                }
                            }
                        }
                    }
                    else
                    {
                        serializationName = attrName;
                    }
                    return serializationName;
                }

                public bool IsNull
                {
                    get
                    {
                        return string.IsNullOrEmpty(SerializationName);
                    }
                }

                public bool LikeArray
                {
                    get
                    {
                        return SerializationName[SerializationName.Length - 1] == ']';
                    }
                }

                unsafe public int ArrayDeep
                {
                    get
                    {
                        if (!LikeArray)
                        {
                            return 0;
                        }
                        int deep = 0;
                        bool sign = false;
                        fixed (char* dst_ = SerializationName)
                        {
                            int len = SerializationName.Length;
                            char* dst = dst_ + len;
                            for (int i = 0; i < len; i++)
                            {
                                switch (*(--dst))
                                {
                                    case '[':
                                        if (!sign)
                                        {
                                            return deep;
                                        }
                                        deep++;
                                        continue;
                                    case ']':
                                        if (sign)
                                        {
                                            return deep;
                                        }
                                        sign = true;
                                        continue;
                                    case ',':
                                        if (!sign)
                                        {
                                            return deep;
                                        }
                                        continue;
                                    default:
                                        return deep;
                                }
                            }
                        }
                        return deep;
                    }
                }

                unsafe static private int FirstArrayBracket(string name)
                {
                    int start = -1;
                    bool sign = false;
                    fixed (char* dst_ = name)
                    {
                        int len = name.Length;
                        char* dst = dst_ + len;
                        for (int i = 0; i < len; i++)
                        {
                            switch (*(--dst))
                            {
                                case '[':
                                    if (!sign)
                                    {
                                        return start;
                                    }
                                    sign = false;
                                    start = len - i - 1;
                                    continue;
                                case ']':
                                    if (sign)
                                    {
                                        return start;
                                    }
                                    sign = true;
                                    continue;
                                case ',':
                                    if (!sign)
                                    {
                                        return start;
                                    }
                                    continue;
                                default:
                                    return start;
                            }
                        }
                    }
                    return start;
                }

                public int FirstBracket
                {
                    get
                    {
                        if (!LikeArray)
                        {
                            return -1;
                        }
                        return FirstArrayBracket(SerializationName);
                    }
                }

                public int ArrayRank
                {
                    get
                    {
                        if (!LikeArray)
                        {
                            return 0;
                        }
                        int lastBracket = SerializationName.LastIndexOf("[");
                        if (lastBracket == -1)
                        {
                            return -1;
                        }
                        int rank = SerializationName.Length - lastBracket - 1;
                        if (rank <= 0 && rank >= ArrayTails.Length)
                        {
                            return -1;
                        }
                        string tail = ArrayTails[rank];
                        for (int i = 0; i <= rank; i++)
                        {
                            if (SerializationName[lastBracket + i] != tail[i])
                            {
                                return -1;
                            }
                        }
                        return rank;
                    }
                }
            }

            struct MemberInfo
            {
                public string MemberName;
                public Func<object, object> GetValue;
                public Action<object, object> SetValue;
                public Type MemberType;
            }

            class MembersInfo
            {
                public bool IsLostTuple;
                public Func<object> New;
                public MemberInfo[] Members;
            }

            struct CacheNode<K, V>
            {
                public K Key;
                public V Value;
            }

            class CacheQueue<Key, Value>
            {
                public int FixCount;
                public LinkedList<CacheNode<Key, Value>> Queue = new LinkedList<CacheNode<Key, Value>>();
                public ConcurrentDictionary<Key, LinkedListNode<CacheNode<Key, Value>>> Cache = new ConcurrentDictionary<Key, LinkedListNode<CacheNode<Key, Value>>>();
            }

            private const int _maxCache = 10000;
            static private bool _initialized = false;
            static private readonly CacheQueue<string, Type> _nameTypeCache = new CacheQueue<string, Type>();
            static private readonly CacheQueue<Type, MembersInfo> _memberCache = new CacheQueue<Type, MembersInfo>();
            static private readonly ConcurrentDictionary<Type, TypeInfo> _typeInfoCache = new ConcurrentDictionary<Type, TypeInfo>();
            static private readonly Func<Type, bool, int> SizeOf = functional.init(delegate ()
            {
                Initialize();
                return CreateCall<Func<Type, bool, int>>(typeof(Marshal).GetMethod("SizeOfHelper", BindingFlags.Static | BindingFlags.NonPublic));
            });

            static private bool TryGetCache<Key, Value>(CacheQueue<Key, Value> cache, Key key, out Value value, bool update = true)
            {
                if (cache.Cache.TryGetValue(key, out var oldNode))
                {
                    value = oldNode.Value.Value;
                    if (update && (cache.Cache.Count - cache.FixCount) > (_maxCache >> 1) && oldNode.List != null)
                    {
                        lock (cache.Queue)
                        {
                            if (oldNode.List != null)
                            {
                                cache.Queue.Remove(oldNode);
                                cache.Queue.AddLast(oldNode);
                            }
                        }
                    }
                    return true;
                }
                value = default;
                return false;
            }

            static private void TryAddCache<Key, Value>(CacheQueue<Key, Value> cache, Key key, Value value, bool update = true)
            {
                var newNode = new LinkedListNode<CacheNode<Key, Value>>(new CacheNode<Key, Value> { Key = key, Value = value });
                if (!update)
                {
                    cache.Cache.TryAdd(key, newNode);
                    return;
                }
                lock (cache.Queue)
                {
                    cache.Queue.AddLast(newNode);
                }
                if (cache.Cache.TryAdd(key, newNode))
                {
                    while ((cache.Cache.Count - cache.FixCount) > _maxCache)
                    {
                        Key oldKey = default;
                        lock (cache.Queue)
                        {
                            var firstNode = cache.Queue.First;
                            if (firstNode == null)
                            {
                                return;
                            }
                            oldKey = firstNode.Value.Key;
                            cache.Queue.Remove(firstNode);
                        }
                        cache.Cache.TryRemove(oldKey, out var _);
                    }
                }
                else
                {
                    lock (cache.Queue)
                    {
                        if (newNode.List != null)
                        {
                            cache.Queue.Remove(newNode);
                        }
                    }
                }
            }

            static internal void Initialize()
            {
                if (_initialized)
                {
                    return;
                }
                lock (_nameTypeCache.Cache)
                {
                    if (_initialized)
                    {
                        return;
                    }
                    assert.check(BitConverter.IsLittleEndian, "");
                    Type[] baseTypes = new Type[]
                    {
                        typeof(bool),
                        typeof(byte),
                        typeof(sbyte),
                        typeof(char),
                        typeof(short),
                        typeof(ushort),
                        typeof(int),
                        typeof(uint),
                        typeof(long),
                        typeof(ulong),
                        typeof(float),
                        typeof(double),
                        typeof(decimal),
                        typeof(string),
                        typeof(object),
                        typeof(DateTime),
                    };
                    foreach (var type in baseTypes)
                    {
                        string attrName = type.FullName;
                        TryAddCache(_nameTypeCache, attrName, type, false);
                        Type arrType = type;
                        string arrName = attrName;
                        for (int i = 0; i < 4; i++)
                        {
                            arrName += "[]";
                            arrType = arrType.MakeArrayType();
                            TryAddCache(_nameTypeCache, arrName, arrType, false);
                        }
                    }
                    var tupleNameDict = new ConcurrentDictionary<string, void_type>();
                    foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
                    {
                        try
                        {
                            foreach (var type in assembly.GetTypes())
                            {
                                var nameAttr = (ParamTuple)Attribute.GetCustomAttribute(type, typeof(ParamTuple), false);
                                if (nameAttr == null)
                                {
                                    continue;
                                }
                                if (!type.IsValueType)
                                {
                                    Type baseType = type.BaseType;
                                    while (baseType != typeof(object))
                                    {
                                        var baseAttr = Attribute.GetCustomAttribute(baseType, typeof(ParamTuple), false);
                                        assert.check(baseAttr != null, $"Rpc.ParamTuple 继承于非 Rpc.ParamTuple 类\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                        baseType = baseType.BaseType;
                                    }
                                }
                                var typeName = nameAttr.Name;
                                if (string.IsNullOrEmpty(typeName))
                                {
                                    assert.check(false, $"Rpc.ParamTuple 类名称未定义\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                }
                                if (typeName.Length > 255)
                                {
                                    assert.check(false, $"Rpc.ParamTuple 类名称长度错误\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                }
                                assert.check(Methods.CheckName(typeName), $"Rpc.ParamTuple 类命名错误 {typeName}\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                typeName = string.Concat(type.Namespace, ".", typeName);
                                if (!tupleNameDict.TryAdd(typeName, default))
                                {
                                    assert.check(false, $"Rpc.ParamTuple 类名称 {typeName} 重复\r\n\r\n{type.Assembly.FullName}.{type.FullName}");
                                }
                                TryAddCache(_nameTypeCache, typeName, type, false);
                                if (type.IsGenericType || type.IsAbstract)
                                {
                                    var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                                    var fieldNameDict = new ConcurrentDictionary<string, void_type>();
                                    for (int i = 0; i < fields.Length; i++)
                                    {
                                        var fieldNameAttr = (ParamName)Attribute.GetCustomAttribute(fields[i], typeof(ParamName), false);
                                        if (fieldNameAttr == null)
                                        {
                                            continue;
                                        }
                                        var fieldName = fieldNameAttr.Name;
                                        if (string.IsNullOrEmpty(fieldName))
                                        {
                                            assert.check(false, $"Rpc.ParamTuple 字段名称未定义\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].Name}");
                                        }
                                        if (fieldName.Length > 255)
                                        {
                                            assert.check(false, $"Rpc.ParamTuple 字段名称长度错误\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].Name}");
                                        }
                                        assert.check(Methods.CheckName(fieldName), $"Rpc.ParamTuple 字段名称错误 {fieldName}\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].Name}");
                                        if (!fieldNameDict.TryAdd(fieldName, default))
                                        {
                                            assert.check(false, $"Rpc.ParamTuple 定义字段名称 {fieldName} 重复\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].Name}");
                                        }
                                    }
                                    continue;
                                }
                                _typeInfoCache.TryAdd(type, new TypeInfo(type) { Internal = nameAttr.Internal });
                                Type arrType = type;
                                string arrName = typeName;
                                for (int i = 0; i < 4; i++)
                                {
                                    arrName += "[]";
                                    arrType = arrType.MakeArrayType();
                                    TryAddCache(_nameTypeCache, arrName, arrType, false);
                                    _typeInfoCache.TryAdd(arrType, new TypeInfo(arrType));
                                }
                                GetMembersInfo(type, false);
                            }
                        }
                        catch (ReflectionTypeLoadException) { }
                    }
                    _nameTypeCache.FixCount = _nameTypeCache.Cache.Count;
                    _memberCache.FixCount = _memberCache.Cache.Count;
                    _initialized = true;
                }
            }

            private int origin;
            private MemoryStream stream;
            private BinaryWriter writer;
            private BinaryReader reader;

            public Serializer(byte[] buffer, int index, int count)
            {
                if (buffer == null)
                    throw new ArgumentNullException(nameof(buffer));
                origin = index;
                stream = new MemoryStream(buffer, index, count, true, true);
                writer = new BinaryWriter(stream);
                reader = new BinaryReader(stream);
            }

            public byte[] Buffer
            {
                get { return stream.GetBuffer(); }
            }

            public int Position
            {
                get { return (int)stream.Position; }
                set { stream.Position = value; }
            }

            unsafe static private void CopyBytes(byte* dst, byte* src, int length)
            {
                for (int i = length; i > 0; i--)
                {
                    *(dst++) = *(src++);
                }
            }

            unsafe private void WriteBytes<T>(T* array, int length) where T : unmanaged
            {
                byte[] dstBuf = stream.GetBuffer();
                int pos = (int)stream.Position;
                int dstOrg = origin + pos;
                int dstLen = dstBuf.Length - dstOrg;
                int srcLen = length * sizeof(T);
                if (srcLen > dstLen)
                    throw new IOException("写入流长度溢出");
                fixed (byte* dst = dstBuf)
                    CopyBytes(dst + dstOrg, (byte*)array, srcLen);
                stream.Position = pos + srcLen;
            }

            unsafe private void ReadBytes<T>(T* array, int length) where T : unmanaged
            {
                byte[] srcBuf = stream.GetBuffer();
                int pos = (int)stream.Position;
                int srcOrg = origin + pos;
                int srcLen = srcBuf.Length - srcOrg;
                int dstLen = length * sizeof(T);
                if (dstLen > srcLen)
                    throw new IOException("读取流长度溢出");
                fixed (byte* src = srcBuf)
                    CopyBytes((byte*)array, src + srcOrg, dstLen);
                stream.Position = pos + dstLen;
            }

            unsafe private void WriteBytes1D<T>(T[] array, int length) where T : unmanaged
            {
                fixed (T* src = array) WriteBytes(src, length);
            }

            unsafe private void ReadBytes1D<T>(T[] array, int length) where T : unmanaged
            {
                fixed (T* dst = array) ReadBytes(dst, length);
            }

            unsafe private void WriteBytes2D<T>(T[,] array, int length) where T : unmanaged
            {
                fixed (T* src = array) WriteBytes(src, length);
            }

            unsafe private void ReadBytes2D<T>(T[,] array, int length) where T : unmanaged
            {
                fixed (T* dst = array) ReadBytes(dst, length);
            }

            unsafe private void WriteBytes3D<T>(T[,,] array, int length) where T : unmanaged
            {
                fixed (T* src = array) WriteBytes(src, length);
            }

            unsafe private void ReadBytes3D<T>(T[,,] array, int length) where T : unmanaged
            {
                fixed (T* dst = array) ReadBytes(dst, length);
            }

            unsafe private void WriteBytes4D<T>(T[,,,] array, int length) where T : unmanaged
            {
                fixed (T* src = array) WriteBytes(src, length);
            }

            unsafe private void ReadBytes4D<T>(T[,,,] array, int length) where T : unmanaged
            {
                fixed (T* dst = array) ReadBytes(dst, length);
            }

            private bool WriteBytesMD(Array array, Type elementType, int rank)
            {
                int length = array.Length;
                switch (Type.GetTypeCode(elementType))
                {
                    case TypeCode.Boolean:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((bool[])array, length); return true;
                            case 2: WriteBytes2D((bool[,])array, length); return true;
                            case 3: WriteBytes3D((bool[,,])array, length); return true;
                            case 4: WriteBytes4D((bool[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Char:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((char[])array, length); return true;
                            case 2: WriteBytes2D((char[,])array, length); return true;
                            case 3: WriteBytes3D((char[,,])array, length); return true;
                            case 4: WriteBytes4D((char[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.SByte:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((sbyte[])array, length); return true;
                            case 2: WriteBytes2D((sbyte[,])array, length); return true;
                            case 3: WriteBytes3D((sbyte[,,])array, length); return true;
                            case 4: WriteBytes4D((sbyte[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Byte:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((byte[])array, length); return true;
                            case 2: WriteBytes2D((byte[,])array, length); return true;
                            case 3: WriteBytes3D((byte[,,])array, length); return true;
                            case 4: WriteBytes4D((byte[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int16:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((short[])array, length); return true;
                            case 2: WriteBytes2D((short[,])array, length); return true;
                            case 3: WriteBytes3D((short[,,])array, length); return true;
                            case 4: WriteBytes4D((short[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt16:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((ushort[])array, length); return true;
                            case 2: WriteBytes2D((ushort[,])array, length); return true;
                            case 3: WriteBytes3D((ushort[,,])array, length); return true;
                            case 4: WriteBytes4D((ushort[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int32:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((int[])array, length); return true;
                            case 2: WriteBytes2D((int[,])array, length); return true;
                            case 3: WriteBytes3D((int[,,])array, length); return true;
                            case 4: WriteBytes4D((int[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt32:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((uint[])array, length); return true;
                            case 2: WriteBytes2D((uint[,])array, length); return true;
                            case 3: WriteBytes3D((uint[,,])array, length); return true;
                            case 4: WriteBytes4D((uint[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int64:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((long[])array, length); return true;
                            case 2: WriteBytes2D((long[,])array, length); return true;
                            case 3: WriteBytes3D((long[,,])array, length); return true;
                            case 4: WriteBytes4D((long[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt64:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((ulong[])array, length); return true;
                            case 2: WriteBytes2D((ulong[,])array, length); return true;
                            case 3: WriteBytes3D((ulong[,,])array, length); return true;
                            case 4: WriteBytes4D((ulong[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Single:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((float[])array, length); return true;
                            case 2: WriteBytes2D((float[,])array, length); return true;
                            case 3: WriteBytes3D((float[,,])array, length); return true;
                            case 4: WriteBytes4D((float[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Double:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((double[])array, length); return true;
                            case 2: WriteBytes2D((double[,])array, length); return true;
                            case 3: WriteBytes3D((double[,,])array, length); return true;
                            case 4: WriteBytes4D((double[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Decimal:
                        switch (rank)
                        {
                            case 1: WriteBytes1D((decimal[])array, length); return true;
                            case 2: WriteBytes2D((decimal[,])array, length); return true;
                            case 3: WriteBytes3D((decimal[,,])array, length); return true;
                            case 4: WriteBytes4D((decimal[,,,])array, length); return true;
                            default: return false;
                        }
                    default:
                        return false;
                }
            }

            private bool ReadBytesMD(Array array, Type elementType, int rank)
            {
                int length = array.Length;
                switch (Type.GetTypeCode(elementType))
                {
                    case TypeCode.Boolean:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((bool[])array, length); return true;
                            case 2: ReadBytes2D((bool[,])array, length); return true;
                            case 3: ReadBytes3D((bool[,,])array, length); return true;
                            case 4: ReadBytes4D((bool[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Char:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((char[])array, length); return true;
                            case 2: ReadBytes2D((char[,])array, length); return true;
                            case 3: ReadBytes3D((char[,,])array, length); return true;
                            case 4: ReadBytes4D((char[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.SByte:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((sbyte[])array, length); return true;
                            case 2: ReadBytes2D((sbyte[,])array, length); return true;
                            case 3: ReadBytes3D((sbyte[,,])array, length); return true;
                            case 4: ReadBytes4D((sbyte[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Byte:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((byte[])array, length); return true;
                            case 2: ReadBytes2D((byte[,])array, length); return true;
                            case 3: ReadBytes3D((byte[,,])array, length); return true;
                            case 4: ReadBytes4D((byte[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int16:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((short[])array, length); return true;
                            case 2: ReadBytes2D((short[,])array, length); return true;
                            case 3: ReadBytes3D((short[,,])array, length); return true;
                            case 4: ReadBytes4D((short[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt16:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((ushort[])array, length); return true;
                            case 2: ReadBytes2D((ushort[,])array, length); return true;
                            case 3: ReadBytes3D((ushort[,,])array, length); return true;
                            case 4: ReadBytes4D((ushort[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int32:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((int[])array, length); return true;
                            case 2: ReadBytes2D((int[,])array, length); return true;
                            case 3: ReadBytes3D((int[,,])array, length); return true;
                            case 4: ReadBytes4D((int[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt32:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((uint[])array, length); return true;
                            case 2: ReadBytes2D((uint[,])array, length); return true;
                            case 3: ReadBytes3D((uint[,,])array, length); return true;
                            case 4: ReadBytes4D((uint[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Int64:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((long[])array, length); return true;
                            case 2: ReadBytes2D((long[,])array, length); return true;
                            case 3: ReadBytes3D((long[,,])array, length); return true;
                            case 4: ReadBytes4D((long[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.UInt64:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((ulong[])array, length); return true;
                            case 2: ReadBytes2D((ulong[,])array, length); return true;
                            case 3: ReadBytes3D((ulong[,,])array, length); return true;
                            case 4: ReadBytes4D((ulong[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Single:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((float[])array, length); return true;
                            case 2: ReadBytes2D((float[,])array, length); return true;
                            case 3: ReadBytes3D((float[,,])array, length); return true;
                            case 4: ReadBytes4D((float[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Double:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((double[])array, length); return true;
                            case 2: ReadBytes2D((double[,])array, length); return true;
                            case 3: ReadBytes3D((double[,,])array, length); return true;
                            case 4: ReadBytes4D((double[,,,])array, length); return true;
                            default: return false;
                        }
                    case TypeCode.Decimal:
                        switch (rank)
                        {
                            case 1: ReadBytes1D((decimal[])array, length); return true;
                            case 2: ReadBytes2D((decimal[,])array, length); return true;
                            case 3: ReadBytes3D((decimal[,,])array, length); return true;
                            case 4: ReadBytes4D((decimal[,,,])array, length); return true;
                            default: return false;
                        }
                    default:
                        return false;
                }
            }

            public int Serialize(object obj)
            {
                if (obj == null)
                    throw new ArgumentNullException(nameof(obj));
                SerializeObject(obj, obj.GetType());
                return (int)stream.Position;
            }

            public object Deserialize()
            {
                return DeserializeObjectDynamic();
            }

            private void SerializeObject(object obj, Type type)
            {
                if (obj == null)
                {
                    writer.Write((byte)TypeCode.Empty);
                    return;
                }
                if (type == typeof(object))
                {
                    type = obj.GetType();
                }
                byte typeCode = (byte)Type.GetTypeCode(type);
                writer.Write(typeCode);
                if (typeCode != (byte)TypeCode.Object)
                {
                    SerializePrimitive(obj, typeCode);
                    return;
                }
                bool addCache = false;
                try
                {
                    if (!_typeInfoCache.TryGetValue(type, out var typeInfo))
                    {
                        typeInfo = new TypeInfo(type);
                        _typeInfoCache.TryAdd(type, typeInfo);
                        addCache = true;
                    }
                    writer.Write(typeInfo.SerializationName);
                    if (typeInfo.LikeArray)
                    {
                        var deep = typeInfo.ArrayDeep;
                        if (deep > 4)
                        {
                            throw new SerializationException($"{type.FullName} 数组异常", type.Assembly.FullName);
                        }
                        if (deep <= 0)
                        {
                            throw new SerializationException("未知异常", "");
                        }
                        var rank = typeInfo.ArrayRank;
                        if (rank <= 0)
                        {
                            throw new SerializationException($"{type.FullName} 数组异常", type.Assembly.FullName);
                        }
                        SerializeArray(obj, type, rank);
                        return;
                    }
                    writer.Write(typeInfo.Internal);
                    SerializeMembers(obj, type, typeInfo.Internal);
                }
                catch
                {
                    if (addCache)
                    {
                        _typeInfoCache.TryRemove(type, out var _);
                    }
                    throw;
                }
            }

            private object DeserializeObjectDynamic()
            {
                byte typeCode = reader.ReadByte();
                if (typeCode == (byte)TypeCode.Empty)
                {
                    return null;
                }
                if (typeCode != (byte)TypeCode.Object)
                {
                    DeserializePrimitive(typeCode, out object obj);
                    return obj;
                }
                var typeInfo = new TypeInfo
                {
                    SerializationName = reader.ReadString(),
                };
                if (typeInfo.IsNull)
                {
                    throw new DeserializeException("名称为空", "");
                }
                var deep = typeInfo.ArrayDeep;
                if (deep > 4)
                {
                    throw new DeserializeException("数组异常", "");
                }
                var type = ResolveType(typeInfo);
                if (typeInfo.LikeArray)
                {
                    if (deep <= 0)
                    {
                        throw new DeserializeException("未知异常", "");
                    }
                    var rank = typeInfo.ArrayRank;
                    if (rank <= 0)
                    {
                        throw new DeserializeException("数组异常", "");
                    }
                    if (type != null)
                    {
                        return DeserializeArray(type, rank);
                    }
                    return DeserializeUnkownArray(rank);
                }
                var isInternal = reader.ReadBoolean();
                if (type != null)
                {
                    return DeserializeMembers(type, isInternal);
                }
                if (isInternal)
                {
                    throw new DeserializeException("未知异常", "");
                }
                return DeserializeUnkownMembers();
            }

            static private Type ResolveType(TypeInfo typeInfo)
            {
                var serializationName = typeInfo.SerializationName;
                if (string.IsNullOrEmpty(serializationName))
                {
                    throw new DeserializeException("", "");
                }
                if (TryGetCache(_nameTypeCache, serializationName, out var cacheType))
                {
                    return cacheType;
                }
                int firstBracket = typeInfo.FirstBracket;
                int firstGeneric = typeInfo.SerializationName.IndexOf('<');
                bool arrayType = firstBracket > 0;
                bool genericType = firstGeneric > 0;
                if (arrayType && firstBracket == -1)
                {
                    throw new DeserializeException(serializationName, "");
                }
                string genericName = null;
                string elementName = null;
                if (!arrayType && !genericType)
                {
                    goto unkown;
                }
                Type resolvedType = null;
                if (genericType)
                {
                    genericName = serializationName.Substring(0, firstGeneric);
                    if (!TryGetCache(_nameTypeCache, genericName, out resolvedType))
                    {
                        goto unkown;
                    }
                    if (resolvedType == null)
                    {
                        goto unkown;
                    }
                    int genCount = 0;
                    int layer = 1;
                    int baseLen = arrayType ? firstBracket : serializationName.Length;
                    for (int i = firstGeneric + 1; i < baseLen; i++)
                    {
                        switch (serializationName[i])
                        {
                            case '<':
                                layer++;
                                break;
                            case '>':
                                layer--;
                                if (layer == 0)
                                {
                                    genCount++;
                                }
                                else if (layer < 0)
                                {
                                    throw new DeserializeException(serializationName, "");
                                }
                                break;
                        }
                    }
                    if (layer != 0)
                    {
                        throw new DeserializeException(serializationName, "");
                    }
                    Type[] genArgs = new Type[genCount];
                    int begin = firstGeneric;
                    genCount = 0;
                    layer = 1;
                    for (int i = firstGeneric + 1; i < baseLen; i++)
                    {
                        switch (serializationName[i])
                        {
                            case '<':
                                if (layer == 0)
                                {
                                    begin = i;
                                }
                                layer++;
                                break;
                            case '>':
                                layer--;
                                if (layer == 0)
                                {
                                    string genArg = serializationName.Substring(begin + 1, i - begin - 1);
                                    Type tempType = ResolveType(new TypeInfo { SerializationName = genArg });
                                    if (tempType == null)
                                    {
                                        goto unkown;
                                    }
                                    genArgs[genCount++] = tempType;
                                }
                                break;
                        }
                    }
                    resolvedType = resolvedType.MakeGenericType(genArgs);
                    if (!arrayType)
                    {
                        TryAddCache(_nameTypeCache, serializationName, resolvedType);
                        return resolvedType;
                    }
                    elementName = serializationName.Substring(0, firstBracket);
                    TryAddCache(_nameTypeCache, elementName, resolvedType);
                }
                else
                {
                    elementName = serializationName.Substring(0, firstBracket);
                    if (!TryGetCache(_nameTypeCache, elementName, out resolvedType))
                    {
                        goto unkown;
                    }
                    if (resolvedType == null)
                    {
                        goto unkown;
                    }
                }
                int lastBracket = firstBracket;
                for (int i = lastBracket + 1; i < serializationName.Length; i++)
                {
                    char c = serializationName[i];
                    switch (c)
                    {
                        case '[':
                            if (lastBracket != -1)
                            {
                                throw new DeserializeException(serializationName, "");
                            }
                            lastBracket = i;
                            break;
                        case ']':
                            if (lastBracket == -1)
                            {
                                throw new DeserializeException(serializationName, "");
                            }
                            int rank = i - lastBracket;
                            if (rank == 1)
                            {
                                resolvedType = resolvedType.MakeArrayType();
                            }
                            else if (rank <= 4)
                            {
                                resolvedType = resolvedType.MakeArrayType(rank);
                            }
                            else
                            {
                                throw new DeserializeException(serializationName, "");
                            }
                            lastBracket = -1;
                            break;
                        case ',':
                            break;
                        default:
                            throw new DeserializeException(serializationName, "");
                    }
                }
                TryAddCache(_nameTypeCache, serializationName, resolvedType);
                return resolvedType;
unkown:
                if (genericType)
                {
                    if (genericName == null)
                    {
                        genericName = serializationName.Substring(0, firstGeneric);
                    }
                    TryAddCache(_nameTypeCache, genericName, null);
                }
                if (arrayType)
                {
                    if (elementName == null)
                    {
                        elementName = serializationName.Substring(0, firstBracket);
                    }
                    TryAddCache(_nameTypeCache, elementName, null);
                }
                TryAddCache(_nameTypeCache, serializationName, null);
                return null;
            }

            private void SerializePrimitive(object obj, int typeCode)
            {
                switch ((TypeCode)typeCode)
                {
                    case TypeCode.Boolean: writer.Write((bool)obj); break;
                    case TypeCode.Byte: writer.Write((byte)obj); break;
                    case TypeCode.SByte: writer.Write((sbyte)obj); break;
                    case TypeCode.Char: writer.Write((char)obj); break;
                    case TypeCode.Int16: writer.Write((short)obj); break;
                    case TypeCode.UInt16: writer.Write((ushort)obj); break;
                    case TypeCode.Int32: writer.Write((int)obj); break;
                    case TypeCode.UInt32: writer.Write((uint)obj); break;
                    case TypeCode.Int64: writer.Write((long)obj); break;
                    case TypeCode.UInt64: writer.Write((ulong)obj); break;
                    case TypeCode.Single: writer.Write((float)obj); break;
                    case TypeCode.Double: writer.Write((double)obj); break;
                    case TypeCode.Decimal: writer.Write((decimal)obj); break;
                    case TypeCode.String: writer.Write((string)obj); break;
                    case TypeCode.DateTime: writer.Write(((DateTime)obj).Ticks); break;
                    default:
                        Type type = obj.GetType();
                        throw new SerializationException($"{type.FullName}, TypeCode {typeCode}", type.Assembly.FullName);
                }
            }

            private void DeserializePrimitive(int typeCode, out object result)
            {
                switch ((TypeCode)typeCode)
                {
                    case TypeCode.Boolean: result = reader.ReadBoolean(); break;
                    case TypeCode.Byte: result = reader.ReadByte(); break;
                    case TypeCode.SByte: result = reader.ReadSByte(); break;
                    case TypeCode.Char: result = reader.ReadChar(); break;
                    case TypeCode.Int16: result = reader.ReadInt16(); break;
                    case TypeCode.UInt16: result = reader.ReadUInt16(); break;
                    case TypeCode.Int32: result = reader.ReadInt32(); break;
                    case TypeCode.UInt32: result = reader.ReadUInt32(); break;
                    case TypeCode.Int64: result = reader.ReadInt64(); break;
                    case TypeCode.UInt64: result = reader.ReadUInt64(); break;
                    case TypeCode.Single: result = reader.ReadSingle(); break;
                    case TypeCode.Double: result = reader.ReadDouble(); break;
                    case TypeCode.Decimal: result = reader.ReadDecimal(); break;
                    case TypeCode.String: result = reader.ReadString(); break;
                    case TypeCode.DateTime: result = DateTime.FromBinary(reader.ReadInt64()); break;
                    default:
                        result = null;
                        throw new DeserializeException($"TypeCode {typeCode}", "");
                }
            }

            private void SerializeArray(object arrayObj, Type type, int rank)
            {
                var array = (Array)arrayObj;
                var elementType = type.GetElementType();
                if (rank == 1)
                {
                    var length = array.GetLength(0);
                    var lowerBound = array.GetLowerBound(0);
                    writer.Write(length);
                    writer.Write(lowerBound);
                    if (!WriteBytesMD(array, elementType, rank))
                    {
                        SerializeArrayElementsOneD(array, elementType, lowerBound, length);
                    }
                }
                else
                {
                    bool boundsZero = true;
                    var lengths = new int[rank];
                    var lowerBounds = new int[rank];
                    for (int i = 0; i < rank; i++)
                    {
                        var length = lengths[i] = array.GetLength(i);
                        writer.Write(length);
                    }
                    for (int i = 0; i < rank; i++)
                    {
                        var lowerBound = lowerBounds[i] = array.GetLowerBound(i);
                        boundsZero &= lowerBound == 0;
                        writer.Write(lowerBound);
                    }
                    if (!WriteBytesMD(array, elementType, rank))
                    {
                        if (boundsZero)
                        {
                            SerializeArrayElementsBoundsZero(array, elementType, lowerBounds, lengths);
                        }
                        else
                        {
                            SerializeArrayElements(array, elementType, lowerBounds, lengths);
                        }
                    }
                }
            }

            static private int GetElementSize(Type type)
            {
                switch (Type.GetTypeCode(type))
                {
                    case TypeCode.Boolean:
                    case TypeCode.Byte:
                    case TypeCode.SByte:
                        return 1;
                    case TypeCode.Char:
                    case TypeCode.Int16:
                    case TypeCode.UInt16:
                        return 2;
                    case TypeCode.Int32:
                    case TypeCode.UInt32:
                    case TypeCode.Single:
                        return 4;
                    case TypeCode.Int64:
                    case TypeCode.UInt64:
                    case TypeCode.Double:
                    case TypeCode.DateTime:
                        return 8;
                    case TypeCode.String:
                        return IntPtr.Size;
                    case TypeCode.Decimal:
                        return sizeof(decimal);
                    case TypeCode.Object:
                        if (type.IsValueType)
                        {
                            return SizeOf(type, false);
                        }
                        return IntPtr.Size;
                }
                return int.MaxValue;
            }

            private object DeserializeArray(Type type, int rank)
            {
                var elementType = type.GetElementType();
                var elementSize = GetElementSize(elementType);
                if (rank == 1)
                {
                    var length = reader.ReadInt32();
                    if (length < 0 || length * elementSize > stream.Length - stream.Position)
                    {
                        throw new DeserializeException($"{type.FullName} Length错误", type.Assembly.FullName);
                    }
                    var lowerBound = reader.ReadInt32();
                    if (lowerBound < 0)
                    {
                        throw new DeserializeException($"{type.FullName} LowerBound错误", type.Assembly.FullName);
                    }
                    var array = 0 == lowerBound ? Array.CreateInstance(elementType, length) : Array.CreateInstance(elementType, new int[] { length }, new int[] { lowerBound });
                    if (!ReadBytesMD(array, elementType, rank))
                    {
                        DeserializeArrayElementsOneD(array, lowerBound, length);
                    }
                    return array;
                }
                else
                {
                    var lengths = new int[rank];
                    long number = 1;
                    for (int i = 0; i < rank; i++)
                    {
                        var len = reader.ReadInt32();
                        if (len < 0)
                        {
                            throw new DeserializeException($"{type.FullName} Length错误", type.Assembly.FullName);
                        }
                        number *= len;
                        lengths[i] = len;
                    }
                    if (number * elementSize > stream.Length - stream.Position)
                    {
                        throw new DeserializeException($"{type.FullName} Length错误", type.Assembly.FullName);
                    }
                    bool boundsZero = true;
                    var lowerBounds = new int[rank];
                    for (int i = 0; i < rank; i++)
                    {
                        var lowerBound = lowerBounds[i] = reader.ReadInt32();
                        if (lowerBound < 0)
                        {
                            throw new DeserializeException($"{type.FullName} LowerBound错误", type.Assembly.FullName);
                        }
                        boundsZero &= lowerBound == 0;
                    }
                    var array = Array.CreateInstance(elementType, lengths, lowerBounds);
                    if (!ReadBytesMD(array, elementType, rank))
                    {
                        if (boundsZero)
                        {
                            DeserializeArrayElementsBoundsZero(array, lowerBounds, lengths);
                        }
                        else
                        {
                            DeserializeArrayElements(array, lowerBounds, lengths);
                        }
                    }
                    return array;
                }
            }

            private object DeserializeUnkownArray(int rank)
            {
                if (rank == 1)
                {
                    var length = reader.ReadInt32();
                    if (length < 0 || length > stream.Length - stream.Position)
                    {
                        throw new DeserializeException("Length错误", "");
                    }
                    var lowerBound = reader.ReadInt32();
                    if (lowerBound < 0)
                    {
                        throw new DeserializeException("LowerBound错误", "");
                    }
                    var array = 0 == lowerBound ? Array.CreateInstance(typeof(object), length) : Array.CreateInstance(typeof(object), new int[] { length }, new int[] { lowerBound });
                    DeserializeArrayElementsOneD(array, lowerBound, length);
                    return array;
                }
                else
                {
                    var lengths = new int[rank];
                    long number = 1;
                    for (int i = 0; i < rank; i++)
                    {
                        var len = reader.ReadInt32();
                        if (len < 0)
                        {
                            throw new DeserializeException("Length错误", "");
                        }
                        number *= len;
                        lengths[i] = len;
                    }
                    if (number > stream.Length - stream.Position)
                    {
                        throw new DeserializeException("Length错误", "");
                    }
                    bool boundsZero = true;
                    var lowerBounds = new int[rank];
                    for (int i = 0; i < rank; i++)
                    {
                        var lowerBound = lowerBounds[i] = reader.ReadInt32();
                        if (lowerBound < 0)
                        {
                            throw new DeserializeException("LowerBound错误", "");
                        }
                        boundsZero &= lowerBound == 0;
                    }
                    var array = Array.CreateInstance(typeof(object), lengths, lowerBounds);
                    if (boundsZero)
                    {
                        DeserializeArrayElementsBoundsZero(array, lowerBounds, lengths);
                    }
                    else
                    {
                        DeserializeArrayElements(array, lowerBounds, lengths);
                    }
                    return array;
                }
            }

            private void SerializeArrayElements(Array array, Type elementType, int[] lowerBounds, int[] lengths)
            {
                var totalElements = array.Length;
                var indices = new int[lowerBounds.Length];
                lowerBounds.CopyTo(indices, 0);
                for (int i = 0; i < totalElements; i++)
                {
                    var element = array.GetValue(indices);
                    SerializeObject(element, elementType);
                    IncrementIndices(indices, lowerBounds, lengths);
                }
            }

            private void DeserializeArrayElements(Array array, int[] lowerBounds, int[] lengths)
            {
                var totalElements = array.Length;
                var indices = new int[lowerBounds.Length];
                lowerBounds.CopyTo(indices, 0);
                for (int i = 0; i < totalElements; i++)
                {
                    var element = DeserializeObjectDynamic();
                    array.SetValue(element, indices);
                    IncrementIndices(indices, lowerBounds, lengths);
                }
            }

            private void SerializeArrayElementsBoundsZero(Array array, Type elementType, int[] lowerBounds, int[] lengths)
            {
                var totalElements = array.Length;
                var indices = lowerBounds;
                for (int i = 0; i < totalElements; i++)
                {
                    var element = array.GetValue(indices);
                    SerializeObject(element, elementType);
                    IncrementIndicesBoundsZero(indices, lengths);
                }
            }

            private void DeserializeArrayElementsBoundsZero(Array array, int[] lowerBounds, int[] lengths)
            {
                var totalElements = array.Length;
                var indices = lowerBounds;
                for (int i = 0; i < totalElements; i++)
                {
                    var element = DeserializeObjectDynamic();
                    array.SetValue(element, indices);
                    IncrementIndicesBoundsZero(indices, lengths);
                }
            }

            private void SerializeArrayElementsOneD(Array array, Type elementType, int lowerBound, int length)
            {
                var totalElements = length;
                var indices = lowerBound;
                for (int i = 0; i < totalElements; i++)
                {
                    var element = array.GetValue(indices);
                    SerializeObject(element, elementType);
                    indices++;
                }
            }

            private void DeserializeArrayElementsOneD(Array array, int lowerBound, int length)
            {
                var totalElements = length;
                var indices = lowerBound;
                for (int i = 0; i < totalElements; i++)
                {
                    var element = DeserializeObjectDynamic();
                    array.SetValue(element, indices);
                    indices++;
                }
            }

            static private void IncrementIndices(int[] indices, int[] lowerBounds, int[] lengths)
            {
                var rank = indices.Length;
                for (int dimension = rank - 1; dimension >= 0; dimension--)
                {
                    indices[dimension]++;
                    if (indices[dimension] < lowerBounds[dimension] + lengths[dimension])
                    {
                        break;
                    }
                    indices[dimension] = lowerBounds[dimension];
                }
            }

            static private void IncrementIndicesBoundsZero(int[] indices, int[] lengths)
            {
                var rank = indices.Length;
                for (int dimension = rank - 1; dimension >= 0; dimension--)
                {
                    indices[dimension]++;
                    if (indices[dimension] < lengths[dimension])
                    {
                        break;
                    }
                    indices[dimension] = 0;
                }
            }

            private void SerializeMembers(object obj, Type type, bool isInternal)
            {
                var members = GetMembersInfo(type);
                writer.Write(members.Members.Length);
                foreach (var memberInfo in members.Members)
                {
                    if (!isInternal)
                    {
                        writer.Write(memberInfo.MemberName);
                    }
                    var value = memberInfo.GetValue(obj);
                    SerializeObject(value, memberInfo.MemberType);
                }
            }

            unsafe private object DeserializeMembers(Type type, bool isInternal)
            {
                var expectedMembers = GetMembersInfo(type);
                var instance = expectedMembers.New();
                var serializedMemberCount = reader.ReadInt32();
                if (isInternal)
                {
                    if (serializedMemberCount != expectedMembers.Members.Length)
                    {
                        throw new DeserializeException("内部类型不匹配", "");
                    }
                    for (int i = 0; i < serializedMemberCount; i++)
                    {
                        var value = DeserializeObjectDynamic();
                        expectedMembers.Members[i].SetValue(instance, value);
                    }
                }
                else
                {
                    int members = expectedMembers.Members.Length;
                    int offset = (members + 31) >> 5;
                    uint* bitsSet = stackalloc uint[offset];
                    for (int i = 0; i < offset; i++)
                    {
                        bitsSet[i] = 0;
                    }
                    offset = 0;
                    for (int i = 0; i < serializedMemberCount; i++)
                    {
                        var memberName = reader.ReadString();
                        var value = DeserializeObjectDynamic();
                        bool isLost = true;
                        for (int j = 0; j < members; j++)
                        {
                            int k = offset + j;
                            if (k >= members)
                            {
                                k -= members;
                            }
                            int idx = k >> 5;
                            uint bit = 1u << (k & 0x1F);
                            if ((bitsSet[idx] & bit) == 0)
                            {
                                var member = expectedMembers.Members[k];
                                if (memberName == member.MemberName)
                                {
                                    member.SetValue(instance, value);
                                    bitsSet[idx] |= bit;
                                    offset = k + 1;
                                    isLost = false;
                                    break;
                                }
                            }
                        }
                        if (isLost && expectedMembers.IsLostTuple)
                        {
                            ((LostTuple)instance).AddLost(memberName, value);
                        }
                    }
                }
                return instance;
            }

            private object DeserializeUnkownMembers()
            {
                var instance = new Dictionary<string, object>();
                var serializedMemberCount = reader.ReadInt32();
                for (int i = 0; i < serializedMemberCount; i++)
                {
                    var memberName = reader.ReadString();
                    var value = DeserializeObjectDynamic();
                    instance[memberName] = value;
                }
                return instance;
            }

            static private MembersInfo GetMembersInfo(Type type, bool update = true)
            {
                if (TryGetCache(_memberCache, type, out var cached, update))
                {
                    return cached;
                }
                if ((ParamTuple)Attribute.GetCustomAttribute(type, typeof(ParamTuple), false) == null)
                {
                    throw new SerializationException(type.FullName, type.Assembly.FullName);
                }
                int count = 0;
                var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
                var members = new MemberInfo[fields.Length];
                var nameDict = new ConcurrentDictionary<string, void_type>();
                for (int i = 0; i < fields.Length; i++)
                {
                    var fieldNameAttr = (ParamName)Attribute.GetCustomAttribute(fields[i], typeof(ParamName), false);
                    if (fieldNameAttr == null)
                    {
                        continue;
                    }
                    string fieldName = fieldNameAttr.Name;
                    if (string.IsNullOrEmpty(fieldName))
                    {
                        assert.check(false, $"Rpc.ParamTuple 字段名称未定义\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].Name}");
                    }
                    assert.check(Methods.CheckName(fieldName), $"Rpc.ParamTuple 字段名称错误 {fieldName}\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].Name}");
                    if (!nameDict.TryAdd(fieldName, default))
                    {
                        assert.check(false, $"Rpc.ParamTuple 定义字段名称 {fieldName} 重复\r\n\r\n{type.Assembly.FullName}.{type.FullName}.{fields[i].Name}");
                    }
                    count++;
                    members[i].MemberName = fieldName;
                    members[i].MemberType = fields[i].FieldType;
                    members[i].GetValue = type.IsValueType ? CreateStructGetter(fields[i]) : CreateObjectGetter(fields[i]);
                    members[i].SetValue = type.IsValueType ? CreateStructSetter(fields[i]) : CreateObjectSetter(fields[i]);
                }
                if (members.Length != count)
                {
                    var membersBak = members;
                    members = new MemberInfo[count];
                    for (int i = 0, j = 0; i < membersBak.Length; i++)
                    {
                        if (membersBak[i].MemberName != null)
                        {
                            members[j++] = membersBak[i];
                        }
                    }
                }
                MembersInfo result = new MembersInfo();
                result.IsLostTuple = type.IsSubclassOf(typeof(LostTuple));
                result.New = Expression.Lambda<Func<object>>(Expression.Convert(Expression.New(type), typeof(object))).Compile();
                result.Members = members;
                TryAddCache(_memberCache, type, result, update);
                return result;
            }
        }
    }
}
